package com.azier.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.io.*;

/**
 * @author 金建强(ptma/@163.com)
 * @version 2017/5/10 13:49
 */
public class ImageUtil {

    public static final String IMAGE_TYPE_GIF  = "gif"; // 图形交换格式
    public static final String IMAGE_TYPE_JPG  = "jpg"; // 联合照片专家组
    public static final String IMAGE_TYPE_JPEG = "jpeg";// 联合照片专家组
    public static final String IMAGE_TYPE_BMP  = "bmp"; // 英文Bitmap（位图）的简写，它是Windows操作系统中的标准图像文件格式
    public static final String IMAGE_TYPE_PNG  = "png"; // 可移植网络图形
    public static final String IMAGE_TYPE_PSD  = "psd"; // Photoshop的专用格式Photoshop

    /**
     * 缩放图像（按比例缩放）
     *
     * @param srcImageFile 源图像文件
     * @param destImageFile 缩放后的图像文件
     * @param scale 缩放比例 0-1
     */
    public final static void scale(File srcImageFile, File destImageFile, int scale) throws IOException {
        scale(new FileInputStream(srcImageFile), new FileOutputStream(destImageFile), scale);
    }

    /**
     * 缩放图像（按比例缩放）
     *
     * @param srcImage 源图像文件
     * @param destImage 缩放后的图像文件
     * @param scale 缩放比例 0-1
     */
    public final static void scale(InputStream srcImage, OutputStream destImage, int scale) throws IOException {
        BufferedImage src = ImageIO.read(srcImage); // 读入文件
        int width = src.getWidth(); // 得到源图宽
        int height = src.getHeight(); // 得到源图长
        width = width / scale;
        height = height / scale;
        Image image = src.getScaledInstance(width, height, Image.SCALE_DEFAULT);
        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = tag.getGraphics();
        g.drawImage(image, 0, 0, null); // 绘制缩小后的图
        g.dispose();
        ImageIO.write(tag, IMAGE_TYPE_JPEG, destImage);// 输出到文件流
    }

    /**
     * 缩放图像（按高度和宽度缩放）
     *
     * @param srcImageFile 源图像文件地址
     * @param destImageFile 缩放后的图像地址
     * @param height 缩放后的高度
     * @param width 缩放后的宽度
     */
    public final static void scale(File srcImageFile, File destImageFile, int height, int width)
        throws IOException {
        scale(new FileInputStream(srcImageFile), new FileOutputStream(destImageFile), height, width);
    }

    /**
     * 缩放图像（按高度和宽度缩放）
     *
     * @param srcImage 源图像文件流
     * @param destImage 缩放后的图像文件流
     * @param height 缩放后的高度
     * @param width 缩放后的宽度
     */
    public final static void scale(InputStream srcImage, OutputStream destImage, int height, int width)
            throws IOException {
        try {
            double ratio = 0.0; // 缩放比例

            BufferedImage bi = ImageIO.read(srcImage);
            Image itemp = bi.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH);
            // 计算比例

            if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
                if (bi.getHeight() > bi.getWidth()) {
                    ratio = (Integer.valueOf(height)).doubleValue() / bi.getHeight();
                } else {
                    ratio = (Integer.valueOf(width)).doubleValue() / bi.getWidth();
                }
                AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
                itemp = op.filter(bi, null);
            }
            ImageIO.write(convertToBufferedImage(itemp), IMAGE_TYPE_JPEG, destImage);
        } finally {
            try {
                srcImage.close();
            } catch (IOException ex) {
            }
            try {
                destImage.close();
            } catch (IOException ex) {
            }
        }
    }

    private static BufferedImage convertToBufferedImage(Image image)
    {
        BufferedImage newImage = new BufferedImage(
            image.getWidth(null), image.getHeight(null),
            BufferedImage.TYPE_INT_RGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return newImage;
    }

    /**
     * 图像切割(按指定起点坐标和宽高切割)
     *
     * @param srcImageFile 源图像地址
     * @param destImageFile 切片后的图像地址
     * @param x 目标切片起点坐标X
     * @param y 目标切片起点坐标Y
     * @param width 目标切片宽度
     * @param height 目标切片高度
     */
    public final static void cut(File srcImageFile, File destImageFile, int x, int y, int width, int height) throws IOException {
        cut(new FileInputStream(srcImageFile), new FileOutputStream(destImageFile), x, y, width, height);
    }
    /**
     * 图像切割(按指定起点坐标和宽高切割)
     *
     * @param srcImage 源图像地址
     * @param destImage  切片后的图像地址
     * @param x 目标切片起点坐标X
     * @param y 目标切片起点坐标Y
     * @param width 目标切片宽度
     * @param height 目标切片高度
     */
    public final static void cut(InputStream srcImage, OutputStream destImage, int x, int y, int width, int height)
            throws IOException {
        try {
            BufferedImage bi = ImageIO.read(srcImage);
            int srcWidth = bi.getHeight(); // 源图宽度

            int srcHeight = bi.getWidth(); // 源图高度

            if (srcWidth > 0 && srcHeight > 0) {
                Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
                // 四个参数分别为图像起点坐标和宽高

                // 即: CropImageFilter(int x,int y,int width,int height)

                ImageFilter cropFilter = new CropImageFilter(x, y, width, height);
                Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropFilter));
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图

                g.dispose();
                // 输出为文件
                ImageIO.write(tag, IMAGE_TYPE_JPEG, destImage);
            }
        } finally {
            try {
                srcImage.close();
            } catch (IOException ex) {
            }
            try {
                destImage.close();
            } catch (IOException ex) {
            }
        }
    }

    /**
     * 图像类型转换：GIF->JPG、GIF->PNG、PNG->JPG、PNG->GIF(X)、BMP->PNG
     *
     * @param srcImageFile 源图像文件
     * @param targetFormat 包含格式非正式名称的 String：如JPG、JPEG、GIF等
     * @param destImageFile 目标图像文件
     */
    public final static void convert(File srcImageFile, String targetFormat, File destImageFile) throws IOException {
        BufferedImage src = ImageIO.read(srcImageFile);
        ImageIO.write(src, targetFormat, destImageFile);
    }

    /**
     * 彩色转为黑白
     *
     * @param srcImageFile 源图像地址
     * @param destImageFile 目标图像地址
     */
    public final static void gray(File srcImageFile, File destImageFile) {
        try {
            BufferedImage src = ImageIO.read(srcImageFile);
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
            ColorConvertOp op = new ColorConvertOp(cs, null);
            src = op.filter(src, null);
            ImageIO.write(src, IMAGE_TYPE_JPEG, destImageFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 给图片添加文字水印
     *
     * @param pressText 水印文字
     * @param srcImageFile 源图像地址
     * @param destImageFile 目标图像地址
     * @param fontName 水印的字体名称
     * @param fontStyle 水印的字体样式，例如Font.BOLD
     * @param color 水印的字体颜色
     * @param fontSize 水印的字体大小
     * @param x 修正值
     * @param y 修正值
     * @param alpha 透明度：alpha 必须是范围 [0.0, 1.0] 之内（包含边界值）的一个浮点数字
     */
    public final static void pressText(String pressText, File srcImageFile, File destImageFile, String fontName,
            int fontStyle, Color color, int fontSize, int x, int y, float alpha) throws IOException {
        Image src = ImageIO.read(srcImageFile);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.drawImage(src, 0, 0, width, height, null);
        g.setColor(color);
        g.setFont(new Font(fontName, fontStyle, fontSize));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        // 在指定坐标绘制水印文字

        g.drawString(pressText, (width - (getLength(pressText) * fontSize)) / 2 + x, (height - fontSize) / 2 + y);
        g.dispose();
        ImageIO.write((BufferedImage) image, IMAGE_TYPE_JPEG, destImageFile);// 输出到文件流
    }

    /**
     * 给图片添加图片水印
     *
     * @param pressImgFile 水印图片
     * @param srcImageFile 源图像文件
     * @param destImageFile 目标图像文件
     * @param x 修正值。 默认在中间，偏移量相对于中间偏移
     * @param y 修正值。 默认在中间，偏移量相对于中间偏移
     * @param alpha 透明度：alpha 必须是范围 [0.0, 1.0] 之内（包含边界值）的一个浮点数字
     */
    public final static void pressImage(File pressImgFile, File srcImageFile, File destImageFile, int x, int y,
            float alpha) throws IOException {
        Image src = ImageIO.read(srcImageFile);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.drawImage(src, 0, 0, width, height, null);
        // 水印文件

        Image pressImg = ImageIO.read(pressImgFile);
        int pressImgWidth = pressImg.getWidth(null);
        int pressImgHeight = pressImg.getHeight(null);
        x += (width - pressImgWidth) / 2;
        y += (height - pressImgHeight) / 2;
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        g.drawImage(pressImg, x, y, pressImgWidth, pressImgHeight, null);
        // 水印文件结束

        g.dispose();
        ImageIO.write((BufferedImage) image, "JPEG", destImageFile);
    }

    /**
     * 计算text的长度（一个中文算两个字符）
     *
     * @param text 文本
     * @return 字符长度，如：text="中国",返回 2；text="test",返回 2；text="中国ABC",返回 4.
     */
    private final static int getLength(String text) {
        int length = 0;
        for (int i = 0; i < text.length(); i++) {
            if (String.valueOf(text.charAt(i)).getBytes().length > 1) {
                length += 2;
            } else {
                length += 1;
            }
        }
        return length / 2;
    }

}
